﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;

namespace KnowledgeEntity
{
   public enum Article_Status
   {
      CHECKED_IN = 1,
      EDITING = 2,
      WAIT_FOR_APPROVING = 3
   }

   public enum Apply_Result//申请编辑的返回状态
   {
      CHECKED_OUT = 1,//成功签出
      OTHER_USER = 2,//被其他用户编辑
      WAIT_FOR_APPROVING = 3//等待审核
   }

   public class Article
   {
      public int ArticleID { get; set; }
      public string Title { get; set; }
      public string Content { get; set; }
      public int VersionID { get; set; }
      public bool IsCheckedOut { get; set; }
      public DateTime CheckedOutTime { get; set; }
      public Article_Status Status { get; private set; }
      public UserAccount User { get; set; }
      public Category Category { get; set; }
      public Dictionary<string, CustomizedLabel> Labels { get; private set; }
      public void AddLabel(CustomizedLabel label)
      {
         if (Labels == null) Labels = new Dictionary<string, CustomizedLabel>();
         if (!Labels.ContainsKey(label.Code)) Labels.Add(label.Code, label);
      }

      /// <summary>
      /// 以条目ID查询条目最新通过审核的版本内容，但在查询之前先尝试放弃已超时的草稿。
      /// </summary>
      /// <param name="id"></param>
      /// <returns></returns>
      public static Article ViewUpdatedArticleById(int id)
      {
         string query = @"spViewUpdatedArticle";

         return QueryArticle(query, System.Data.CommandType.StoredProcedure, 
            new SqlParameter[]{new SqlParameter{
            ParameterName = "@articleID",
            Direction = System.Data.ParameterDirection.Input,
            DbType = System.Data.DbType.Int32,
            Value = id
         }});
      }

      public static Article GetArticleById(int id)
      {
         return GetArticleById(id, Article_Status.CHECKED_IN);
      }

      /// <summary>
      /// 以条目ID查询条目最新通过审核的版本的内容
      /// </summary>
      /// <param name="id"></param>
      /// <returns></returns>
      public static Article GetArticleById(int id, Article_Status status)
      {
         string query = string.Format(@"select ac.ID, ac.Title, ac.Article, ac.VersionID, ac.IsCheckedOut, ac.CheckedOutTime, ac.Status, ac.UserID
                                            ,lbl.ID as LabelID,lbl.Code as LabelCode,lbl.Description
                                            ,ca.ID, ca.Name, ca.Description, ca.ParentID
                                            from VersionControlledArticle ac
                                            left join Link_Article_Label lnk on ac.ID = lnk.ArticleID
                                            left join CustomizedLabel lbl on lnk.LabelID = lbl.ID
                                            left join Category ca on ca.ID = ac.CategoryID
                                            where ac.id = {0}
                                            and ac.VersionID = (select max(VersionID) from VersionControlledArticle
                                                                where id = {0} and Status = {1})", id, (int)status);
         return QueryArticle(query, System.Data.CommandType.Text, null);
      }

      public static Article GetLatestArticleById(int id)
      {
         string query = string.Format(@"select ac.ID, ac.Title, ac.Article, ac.VersionID, ac.IsCheckedOut, ac.CheckedOutTime, ac.Status, ac.UserID
                                            ,lbl.ID as LabelID,lbl.Code as LabelCode,lbl.Description
                                            ,ca.ID, ca.Name, ca.Description, ca.ParentID
                                            from VersionControlledArticle ac
                                            left join Link_Article_Label lnk on ac.ID = lnk.ArticleID
                                            left join CustomizedLabel lbl on lnk.LabelID = lbl.ID
                                            left join Category ca on ca.ID = ac.CategoryID
                                            where ac.id = {0}
                                            and ac.VersionID = (select max(VersionID) from VersionControlledArticle
                                                                where id = {0})", id);
         return QueryArticle(query, System.Data.CommandType.Text, null);
      }

      private static Article QueryArticle(string query, System.Data.CommandType commandType, SqlParameter[] parameters)
      {
         using (SqlDataReader ArticleReader = DBHelper.SqlHelper.GetReader(query, commandType, parameters))
         {
            Article article = null;
            if (ArticleReader.Read())
            {
               if (article == null)
               {
                  article = new Article
                  {
                     ArticleID = ArticleReader.GetInt32(0),
                     Title = ArticleReader.GetString(1),
                     Content = ArticleReader.GetString(2),
                     VersionID = ArticleReader.GetInt32(3),
                     IsCheckedOut = ArticleReader.GetBoolean(4),
                     CheckedOutTime = ArticleReader.GetDateTime(5), 
                     Status = (Article_Status)ArticleReader.GetInt32(6),
                     User = UserAccountFactory.GetUserInstanceByID(ArticleReader.GetInt32(7))
                  };
               }
               article.AddLabel(new CustomizedLabel
               {
                  Code = ArticleReader.IsDBNull(9) ? string.Empty : ArticleReader.GetString(7),
                  Description = ArticleReader.IsDBNull(10) ? string.Empty : ArticleReader.GetString(8)
               });
               article.Category = new Category(ArticleReader.IsDBNull(11) ? -1 : ArticleReader.GetInt32(11),
                                               ArticleReader.IsDBNull(12) ? string.Empty : ArticleReader.GetString(12));
            }
            ArticleReader.Close();
            return article;
         }
      }

      public static Dictionary<int, Article> GetArticleByLabel(string labelCode)
      {
         return GetArticleByConditionString(string.Empty, string.Format("where lbl.Code = '{0}'", labelCode), string.Empty);
      }

      public static Dictionary<int, Article> GetArticleRecently(int count)
      {
         return GetArticleByConditionString(string.Format("top {0}",count), string.Empty, "order by ac.createTime");
      }

      public static Dictionary<int, Article> GetArticleByConditionString(string prefix, string whereClause, string suffix)
      {
         return GetArticleByConditionString(prefix, whereClause, suffix, Article_Status.CHECKED_IN);
      }

      public static Dictionary<int, Article> GetArticleByConditionString(string prefix, string whereClause, string suffix, Article_Status status)
      {
         string query = string.Format(@"select ac.ID, ac.Title,ac.Article, ac.VersionID,ac.IsCheckedOut, ac.CheckedOutTime, ac.Status, ac.UserID
                                       , lbl.ID,lbl.Code,lbl.Description
                                       ,ca.ID, ca.Name, ca.Description, ca.ParentID
                                       from VersionControlledArticle ac
                                       left join Link_Article_Label lnk on ac.ID = lnk.ArticleID
                                       left join CustomizedLabel lbl on lnk.LabelID = lbl.ID
                                       left join Category ca on ca.ID = ac.CategoryID
                                       where ac.Status = {3} and ac.id in (
                                       select {0} ac.ID from VersionControlledArticle ac
                                       left join Link_Article_Label lnk on ac.ID = lnk.ArticleID
                                       left join CustomizedLabel lb on lnk.LabelID = lbl.ID
                                       {1}
                                       ) {2}", prefix,whereClause, suffix, (int)status);
         using (SqlDataReader ArticleReader = DBHelper.SqlHelper.GetReader(query))
         {
            Dictionary<int, Article> articleList = new Dictionary<int, Article>();

            while (ArticleReader.Read())
            {
               int articleID = ArticleReader.GetInt32(0);

               if (!articleList.ContainsKey(articleID))
               {
                  articleList.Add(articleID, new Article
                  {
                     ArticleID = ArticleReader.GetInt32(0),
                     Title = ArticleReader.GetString(1),
                     Content = ArticleReader.GetString(2),
                     VersionID = ArticleReader.GetInt32(3),
                     IsCheckedOut = ArticleReader.GetBoolean(4),
                     CheckedOutTime = ArticleReader.GetDateTime(5),
                     Status = (Article_Status)ArticleReader.GetInt32(6),
                     User = UserAccountFactory.GetUserInstanceByID(ArticleReader.GetInt32(7))
                  });
               }
               articleList[articleID].AddLabel(new CustomizedLabel
               {
                  Code = ArticleReader.IsDBNull(9) ? string.Empty : ArticleReader.GetString(7),
                  Description = ArticleReader.IsDBNull(10) ? string.Empty : ArticleReader.GetString(8)
               });
               articleList[articleID].Category = new Category(ArticleReader.IsDBNull(11)? -1: ArticleReader.GetInt32(11), 
                                                              ArticleReader.IsDBNull(12)? string.Empty : ArticleReader.GetString(12));
            }

            return articleList;
         }
      }

      /// <summary>
      /// 申请编辑
      /// </summary>
      /// <param name="articleID"></param>
      /// <param name="user"></param>
      /// <returns></returns>
      public static Apply_Result AskForEditing(int articleID, UserAccount user)
      {
         SqlParameter para_articleID = new SqlParameter
         {
            ParameterName = "@articleID",
            DbType = System.Data.DbType.Int32,
            Direction = System.Data.ParameterDirection.Input,
            Value = articleID
         };

         SqlParameter para_userID = new SqlParameter
         {
            ParameterName = "@currentUserID",
            DbType = System.Data.DbType.Int32,
            Direction = System.Data.ParameterDirection.Input,
            Value = user.ID
         };

         SqlParameter returnValue = new SqlParameter
         {
            ParameterName = "@returnValue",
            DbType = System.Data.DbType.String,
            Size = 15,
            Direction = System.Data.ParameterDirection.Output
         };

         DBHelper.SqlHelper.ExecuteNonQuery(@"spAskForEditing", new SqlParameter[] { para_articleID, para_userID }, System.Data.CommandType.StoredProcedure, ref returnValue);

         switch (returnValue.Value + "")
         {
            case "OTHER_USER":
               return Apply_Result.OTHER_USER;
            case "WAIT_APPROVE":
               return Apply_Result.WAIT_FOR_APPROVING;
            default:
            case "CHECKED_OUT":
               return Apply_Result.CHECKED_OUT;
         }
      }

      public static Article EditArticle(Article article)
      {
         SqlParameter[] paramters = new SqlParameter[4];
         paramters[0] = new SqlParameter
         {
            ParameterName = "@articleID",
            DbType = System.Data.DbType.Int32,
            Value = article.ArticleID
         };

         paramters[1] = new SqlParameter
         {
            ParameterName = "@title",
            Value = article.Title
         };

         paramters[2] = new SqlParameter
         {
            ParameterName = "@content",
            Value = article.Content
         };

         paramters[3] = new SqlParameter
         {
            Direction = System.Data.ParameterDirection.ReturnValue
         };

         DBHelper.SqlHelper.ExecuteProcedure("spEditArticle", paramters);

         return GetArticleById(int.Parse(paramters[3].Value + ""));
      }

      public static void AccessArticle(Article article)
      {
         SqlParameter[] paramters = new SqlParameter[1];
         paramters[0] = new SqlParameter
         {
            ParameterName = "@articleID",
            DbType = System.Data.DbType.Int32,
            Value = article.ArticleID
         };

         DBHelper.SqlHelper.ExecuteProcedure("spAccessArticle", paramters);
      }

      /// <summary>
      /// 保存草稿
      /// </summary>
      /// <param name="article"></param>
      /// <returns></returns>
      public static Article SaveDraft(Article article)
      {
         SqlParameter[] parameters = new SqlParameter[] { 
            new SqlParameter{
               ParameterName = "@articleID",
               DbType = System.Data.DbType.Int32,
               Value = article.ArticleID
            },
            new SqlParameter{
               ParameterName = "@versionID",
               DbType = System.Data.DbType.Int32,
               Value = article.VersionID
            },
            new SqlParameter{
               ParameterName = "@title",
               Value = article.Title
            },
            new SqlParameter{
               ParameterName = "@content",
               Value = article.Content
            },
            new SqlParameter{
               ParameterName = "@categoryID",
               DbType = System.Data.DbType.Int32,
               Value = article.Category.ID
            },
            new SqlParameter{
               ParameterName = "@userID",
               DbType = System.Data.DbType.Int32,
               Value = article.User.ID
            }
         };

         DBHelper.SqlHelper.ExecuteProcedure("spSaveDraft", parameters);
         
         return Article.GetArticleById(article.ArticleID, Article_Status.EDITING);
      }

      /// <summary>
      /// 提交审核
      /// </summary>
      /// <param name="article"></param>
      /// <returns></returns>
      public static Article Submit(Article article)
      {
         SqlParameter[] parameters = new SqlParameter[]{
            new SqlParameter{
               ParameterName = "@articleID",
               DbType = System.Data.DbType.Int32,
               Value = article.ArticleID
            },
            new SqlParameter{
               ParameterName = "@versionID",
               DbType = System.Data.DbType.Int32,
               Value = article.VersionID
            },
            new SqlParameter{
               ParameterName = "@title",
               Value = article.Title
            },
            new SqlParameter{
               ParameterName = "@content",
               Value = article.Content
            },
            new SqlParameter{
               ParameterName = "@categoryID",
               DbType = System.Data.DbType.Int32,
               Value = article.Category.ID
            },
            new SqlParameter{
               ParameterName = "@userID",
               DbType = System.Data.DbType.Int32,
               Value = article.User.ID
            }
         };

         DBHelper.SqlHelper.ExecuteProcedure("spSubmitArticle", parameters);

         return Article.GetArticleById(article.ArticleID, Article_Status.WAIT_FOR_APPROVING);
      }

      public static Dictionary<int,Article> GetArticlesToBeApproved()
      {
         return GetArticleByConditionString(string.Empty, string.Empty, string.Empty, Article_Status.WAIT_FOR_APPROVING);
      }

      public void Approve()
      {
         SqlParameter[] parameters = new SqlParameter[]{
            new SqlParameter{
               DbType = System.Data.DbType.Int32,
               ParameterName = "@articleID",
               Value = ArticleID
            },
            new SqlParameter{
               DbType = System.Data.DbType.Int32,
               ParameterName = "@versionID",
               Value = VersionID
            },
         };
         DBHelper.SqlHelper.ExecuteProcedure("spApproveArticle", parameters);
      }

   }
}
